#if XINPUT_ENABLED
#define USING_XINPUT
#endif
using Devil;
using UnityEngine;
#if USING_XINPUT
using XInputDotNetPure;
#endif

namespace GameToolkit
{
    [CreateAssetMenu(fileName = "Xbox Input", menuName = "输入/Xbox 控制器")]
    public class LegencyXboxController : InputController, ITick, InputController.IInputVibrate
    {
        static int vib_id;
        static int GetVibID()
        {
            return ++vib_id;
        }

        public enum EJoystickAxis
        {
            None,
            LPad_X,
            LPad_Y,
            RPad_X,
            RPad_Y,
            Trigger,
            Cross_X,
            Cross_Y,
        }

        KeyInfo[] mKeys = {
            KeyInfo.GetButton(EControllerType.Controller, "A", (int)KeyCode.JoystickButton0),
            KeyInfo.GetButton(EControllerType.Controller,"B", (int)KeyCode.JoystickButton1),
            KeyInfo.GetButton(EControllerType.Controller,"X", (int)KeyCode.JoystickButton2),
            KeyInfo.GetButton(EControllerType.Controller,"Y", (int)KeyCode.JoystickButton3),
            KeyInfo.GetButton(EControllerType.Controller,"SL", (int)KeyCode.JoystickButton4),
            KeyInfo.GetButton(EControllerType.Controller,"SR", (int)KeyCode.JoystickButton5),
            KeyInfo.GetButton(EControllerType.Controller, ECustomizableKey.SystemBack, "BACK", (int)KeyCode.JoystickButton6),
            KeyInfo.GetButton(EControllerType.Controller, ECustomizableKey.SystemStart, "START", (int)KeyCode.JoystickButton7),
            KeyInfo.GetButton(EControllerType.Controller,"LPad", (int)KeyCode.JoystickButton8),
            KeyInfo.GetButton(EControllerType.Controller,"RPad", (int)KeyCode.JoystickButton9),

            KeyInfo.GetAxis(EControllerType.Controller,"LPad X", (int)EJoystickAxis.LPad_X),
            KeyInfo.GetAxis(EControllerType.Controller,"LPad Y", (int)EJoystickAxis.LPad_Y),
            KeyInfo.GetAxis(EControllerType.Controller,"RPad X", (int)EJoystickAxis.RPad_X),
            KeyInfo.GetAxis(EControllerType.Controller,"RPad Y", (int)EJoystickAxis.RPad_Y),
            KeyInfo.GetAxis(EControllerType.Controller,"Trigger", (int)EJoystickAxis.Trigger),
            KeyInfo.GetAxis(EControllerType.Controller,"Cross X", (int)EJoystickAxis.Cross_X),
            KeyInfo.GetAxis(EControllerType.Controller,"Cross Y", (int)EJoystickAxis.Cross_Y),

        };

        //[SerializeField]
        //float m_MaxVibration = 1;
        [SerializeField]
        InputVibrateCurve m_VibrateCurve;

        EaseInputVibrate mLeftVibrate;
        float mLeftVibrateValue;
        EaseInputVibrate mRightVibrate;
        float mRightVibrateValue;

        public override IInputAction GetAction(string keyName)
        {
            for (int i = 0; i < mKeys.Length; i++)
            {
                var key = mKeys[i];
                if (keyName.EqualsIgnoreCase(key.keyName))
                {
                    if (key.isAxis)
                        return new ControllerAxis(key, this);
                    else
                        return new ControllerButton(key, this);
                }
            }
            return null;
        }

        public override KeyInfo[] GetKeysInfo()
        {
            var keys = new KeyInfo[mKeys.Length];
            for (int i = 0; i < keys.Length; i++)
            {
                var key = mKeys[i];
                //key.controller = this;
                keys[i] = key;
            }
            return keys;
        }

        public override EControllerType ControllerType { get { return EControllerType.Controller; } }

        public override bool IsKindOf(EControllerType type)
        {
            return type == EControllerType.Controller;
        }

        public override void Prepare(GameInput ginput)
        {
            base.Prepare(ginput);
            mLeftVibrate = new EaseInputVibrate();
            mRightVibrate = new EaseInputVibrate();
        }

        int IInputVibrate.StartVibration(EVibrationID id, float strength, float duration)
        {
            var vibid = GetVibID();
            if ((id & EVibrationID.Left) != 0 && mLeftVibrate != null)
                mLeftVibrate.AddVibrate(vibid, strength, duration);
            if ((id & EVibrationID.Right) != 0 && mRightVibrate != null)
                mRightVibrate.AddVibrate(vibid, strength, duration);
            return vibid;
        }

        void IInputVibrate.AppendVibration(int id, float duration)
        {
            mLeftVibrate.Append(id, duration);
            mRightVibrate.Append(id, duration);
        }

        void IInputVibrate.StopVibration(int id)
        {
            mLeftVibrate.Stop(id);
            mRightVibrate.Stop(id);
        }

        void ITick.OnTick(float deltaTime)
        {
            if (GameInput.ActiveController == this)
            {
                float l = mLeftVibrateValue, r = mRightVibrateValue;
                mLeftVibrateValue = mLeftVibrate.Evaluate(m_VibrateCurve, deltaTime);
                mRightVibrateValue = mRightVibrate.Evaluate(m_VibrateCurve, deltaTime);
                if (!Mathf.Approximately(l, mLeftVibrateValue) || !Mathf.Approximately(r, mRightVibrateValue))
                {
                    //#if USING_XINPUT
                    //                    GamePad.SetVibration(PlayerIndex.One, mLeftVibrateValue, mRightVibrateValue);
                    //#endif
                }
            }
        }

        protected override bool TestConnection()
        {
            return true;
            //var conn = InputDevices.GetConnectedJoystick();
            //return StringUtil.EqualIgnoreCase(conn, ConfigName) || conn == InputDevices.UNKNOWN_CONTROLLER;
        }

        [System.Serializable]
        public class ControllerButton : IInputAction
        {
            InputController mCtrl;
            KeyInfo mKeyInfo;
            public ControllerButton(KeyInfo key, InputController ct)
            {
                mKeyInfo = key;
                mCtrl = ct;
            }

            public EControllerType ControllerType { get { return EControllerType.Controller; } }
            public InputController Controller { get { return mCtrl; } }
            public bool HasButton
            {
                get
                {
                    return Input.GetKey((KeyCode)mKeyInfo.keyCode);
                }
            }
            public float Value { get { return 0; } }
            public KeyInfo GetKeyInfo()
            {
                return mKeyInfo;
            }
        }

        public class ControllerAxis : IInputAction, ITick
        {
            KeyInfo mKeyInfo;
            string mAxis;
            float mValue;
            InputController mCtrl;

            public ControllerAxis(KeyInfo key, InputController ct)
            {
                mKeyInfo = key;
                mCtrl = ct;
                switch ((EJoystickAxis)key.keyCode)
                {
                    case EJoystickAxis.LPad_X:
                        mAxis = "Joystick LX";
                        break;
                    case EJoystickAxis.LPad_Y:
                        mAxis = "Joystick LY";
                        break;
                    case EJoystickAxis.RPad_X:
                        mAxis = "Joystick RX";
                        break;
                    case EJoystickAxis.RPad_Y:
                        mAxis = "Joystick RY";
                        break;
                    case EJoystickAxis.Trigger:
                        mAxis = "Joystick TR";
                        break;
                    case EJoystickAxis.Cross_X:
                        mAxis = "Joystick CX";
                        break;
                    case EJoystickAxis.Cross_Y:
                        mAxis = "Joystick CY";
                        break;
                    default:
                        break;
                }
            }

            public EControllerType ControllerType { get { return EControllerType.Controller; } }
            public InputController Controller { get { return mCtrl; } }
            public float Value { get { return mValue; } }

            public bool HasButton { get; private set; }

            public KeyInfo GetKeyInfo()
            {
                return mKeyInfo;
            }

            public void OnTick(float deltaTime)
            {
                mValue = Input.GetAxisRaw(mAxis);
                HasButton = mValue < -0.3f || mValue > 0.3f;
            }
        }
    }
}